package cron_task

import (
	"context"
	"github.com/go-kratos/kratos/v2/log"
	"github.com/google/wire"
	"github.com/pkg/errors"
	"go.opentelemetry.io/otel"
	"kratos_cron_task/internal/biz"
	"kratos_cron_task/internal/conf"
	"kratos_cron_task/pkg/task2"
	"kratos_cron_task/pkg/task2/worker"
)

var ProviderSet = wire.NewSet(NewTask)

type task struct {
	ctx     context.Context
	payload worker.Payload
	cronBiz *biz.CronBiz
}

func process(t task) (err error) {
	tr := otel.Tracer("task")
	_, span := tr.Start(t.ctx, "Task")
	defer span.End()
	// worker.WithRunGroup(item.Category) 中的参数
	switch t.payload.Group {
	// Notice 配置文件中 tasks下的category
	case "ta2":
		// 调用biz层的方法～操作 数据库、redis
		errTa2 := t.cronBiz.RunCronTask2Biz(context.Background())
		if errTa2 != nil {
			log.Error(errTa2)
		}
	}
	return
}

func NewTask(c *conf.Bootstrap, cronBiz *biz.CronBiz) (tk *task2.Task, err error) {

	defer func() {
		e := recover()
		if e != nil {
			err = errors.Errorf("初始化Task失败! err: %v", e)
		}
	}()

	// new worker
	w := worker.New(
		// Notice 因为用了 asynq 所以强依赖redis～
		worker.WithRedisUri(c.Data.Redis.Dsn),
		worker.WithGroup(c.Server.Name),
		// 注册处理的方法～
		worker.WithHandler(func(ctx context.Context, p worker.Payload) error {
			// 上面定义好的process
			return process(task{
				ctx:     ctx,
				payload: p,
				cronBiz: cronBiz,
			})
		}),
	)

	if w.Error != nil {
		err = errors.WithMessage(w.Error, "initialize worker failed")
		return
	}

	// 初始化Task
	tk = &task2.Task{
		Worker: w,
	}

	// 配置文件
	if len(c.Tasks) > 0 {
		for _, item := range c.Tasks {
			// Notice 注册定时任务 一次性任务使用 Once 方法～
			err = tk.Worker.Cron(
				worker.WithRunGroup(item.Category),
				worker.WithRunUuid(item.Uuid),
				// 注意下，表达式不同的系统会有区别
				worker.WithRunExpr(item.Expr),
				worker.WithRunTimeout(int(item.Timeout)),
				worker.WithRunMaxRetry(int(item.Retry)),
			)
			if err != nil {
				err = errors.WithMessage(err, "initialize worker failed")
				return
			}
		}
	}

	log.Info("initialize worker success!!!")
	return

}
